#include "Character.h"

// Constructor
Character::Character(void)
: sprite_anim_start				( CHARIMAGE_IDLE_START )
, sprite_anim_end				( CHARIMAGE_IDLE_END )
, sprite_idle_strt				( CHARIMAGE_IDLE_START )
, sprite_idle_end				( CHARIMAGE_IDLE_END )
, sprite_inair_strt				( CHARIMAGE_INAIR_START )
, sprite_inair_end				( CHARIMAGE_INAIR_END )
, sprite_death_strt				( CHARIMAGE_DEATH_START )
, sprite_death_end				( CHARIMAGE_DEATH_END )
, sprite_hurt_strt				( CHARIMAGE_HURT_START )
, sprite_hurt_end				( CHARIMAGE_HURT_END )
, sprite_move_strt				( CHARIMAGE_MOVE_START )
, sprite_move_end				( CHARIMAGE_MOVE_END )
, sprite_pri_atk_track_strt		( CHARIMAGE_PRIMARY_ATTACK_SWORDANDSHIELD_START )
, sprite_pri_atk_track_end		( CHARIMAGE_PRIMARY_ATTACK_SWORDANDSHIELD_END )
, sprite_pri_atk_do_atk			( CHARIMAGE_PRIMARY_ATTACK_SWORDANDSHIELD_START )
, sprite_sec_atk_track_strt		( CHARIMAGE_SECONDARY_ATTACK_SWORDANDSHIELD_START )
, sprite_sec_atk_track_end		( CHARIMAGE_SECONDARY_ATTACK_SWORDANDSHIELD_END )
, sprite_sec_atk_do_atk			( CHARIMAGE_SECONDARY_ATTACK_SWORDANDSHIELD_START )
, char_hit						( false )
, char_dead						( false )
, char_moving					( false )
, char_denymove					( false )
, char_attacking_pri			( false )
, char_attacking_sec			( false )
, char_attack_allow				( false )
, char_status_invul				( false )
, char_jumptracker				( 0.0f )
, weapon_weapon					( NULL )
, weapon_offset_sec				( Vector3D() )
, weapon_sec_atk_key_hold		( false )
, weapon_unlocked				( NULL )
, weapon_level					( NULL )
, weapon_dualsword_tracker_move	( false )
, timer_sprite_char				( 0 )
, theInventory					( NULL )
{
}

// Destructor
Character::~Character(void)
{
	if ( weapon_weapon != NULL )
	{
		delete weapon_weapon;
		weapon_weapon = NULL;
	}

	if ( weapon_unlocked != NULL )
	{
		delete weapon_unlocked;
		weapon_unlocked = NULL;
	}

	if ( weapon_level != NULL )
	{
		delete weapon_level;
		weapon_level = NULL;
	}

	if ( theInventory != NULL )
	{
		delete theInventory;
		theInventory = NULL;
	}
}

// First Initialisation
bool Character::InitialiseDeclare(const CWeapon::WEAPON weaponchoice, MouseInfo *mouseInfo)
{
	theInventory = new Inventory( 4, 6 );
	theInventory->SetMouseInfo( mouseInfo );

	this->Initialise( weaponchoice );
	
	return true;
}

// Initialise Character
bool Character::Initialise(const CWeapon::WEAPON weapon_choice, const Vector3D character_position, const Vector3D hud_position, const Vector3D size, const float lives, const float move_speed)
{
	// Only initialise sprites once
	if ( weapon_unlocked == NULL )
	{
		// Initialise sprites
		this->InitSprite( TOTAL );

		// CHARACTER NORMAL
		this->SetSprite( CHARIMAGE_IDLE_START	, FILEPATH_CHARIMAGE_IDLE_START		);
		this->SetSprite( CHARIMAGE_IDLE_END		, FILEPATH_CHARIMAGE_IDLE_END		);
		//
		this->SetSprite( CHARIMAGE_INAIR_START	, FILEPATH_CHARIMAGE_INAIR_START	);
		this->SetSprite( CHARIMAGE_INAIR_END	, FILEPATH_CHARIMAGE_INAIR_END		);
		//
		this->SetSprite( CHARIMAGE_DEATH_START	, FILEPATH_CHARIMAGE_DEATH_START	);
		this->SetSprite( CHARIMAGE_DEATH_END	, FILEPATH_CHARIMAGE_DEATH_END		);
		//
		this->SetSprite( CHARIMAGE_HURT_START	, FILEPATH_CHARIMAGE_HURT_START		);
		this->SetSprite( CHARIMAGE_HURT_END		, FILEPATH_CHARIMAGE_HURT_END		);
		//
		this->SetSprite( CHARIMAGE_MOVE_START	, FILEPATH_CHARIMAGE_MOVE_START		);
		this->SetSprite( CHARIMAGE_MOVE_1		, FILEPATH_CHARIMAGE_MOVE_1			);
		this->SetSprite( CHARIMAGE_MOVE_2		, FILEPATH_CHARIMAGE_MOVE_2			);
		this->SetSprite( CHARIMAGE_MOVE_3		, FILEPATH_CHARIMAGE_MOVE_3			);
		this->SetSprite( CHARIMAGE_MOVE_4		, FILEPATH_CHARIMAGE_MOVE_4			);
		this->SetSprite( CHARIMAGE_MOVE_END		, FILEPATH_CHARIMAGE_MOVE_END		);
		
		// ATTACK DUALSWORD
		this->SetSprite( CHARIMAGE_PRIMARY_ATTACK_DUALSWORD_START			, FILEPATH_CHARIMAGE_PRIMARY_ATTACK_DUALSWORD_START );
		this->SetSprite( CHARIMAGE_PRIMARY_ATTACK_DUALSWORD_1				, FILEPATH_CHARIMAGE_PRIMARY_ATTACK_LONGSWORD_1 );
		this->SetSprite( CHARIMAGE_PRIMARY_ATTACK_DUALSWORD_END				, FILEPATH_CHARIMAGE_PRIMARY_ATTACK_DUALSWORD_END );
		//
		this->SetSprite( CHARIMAGE_SECONDARY_ATTACK_DUALSWORD_START			, FILEPATH_CHARIMAGE_SECONDARY_ATTACK_DUALSWORD_START );
		this->SetSprite( CHARIMAGE_SECONDARY_ATTACK_DUALSWORD_END			, FILEPATH_CHARIMAGE_SECONDARY_ATTACK_DUALSWORD_END );

		// ATTACK LONGSWORD
		this->SetSprite( CHARIMAGE_PRIMARY_ATTACK_LONGSWORD_START			, FILEPATH_CHARIMAGE_PRIMARY_ATTACK_LONGSWORD_START );
		this->SetSprite( CHARIMAGE_PRIMARY_ATTACK_LONGSWORD_1				, FILEPATH_CHARIMAGE_PRIMARY_ATTACK_LONGSWORD_1 );
		this->SetSprite( CHARIMAGE_PRIMARY_ATTACK_LONGSWORD_END				, FILEPATH_CHARIMAGE_PRIMARY_ATTACK_LONGSWORD_END );
		//
		this->SetSprite( CHARIMAGE_SECONDARY_ATTACK_LONGSWORD_START			, FILEPATH_CHARIMAGE_SECONDARY_ATTACK_LONGSWORD_START );
		this->SetSprite( CHARIMAGE_SECONDARY_ATTACK_LONGSWORD_END			, FILEPATH_CHARIMAGE_SECONDARY_ATTACK_LONGSWORD_END );

		// ATTACK SWORDANDSHIELD
		this->SetSprite( CHARIMAGE_PRIMARY_ATTACK_SWORDANDSHIELD_START		, FILEPATH_CHARIMAGE_PRIMARY_ATTACK_SWORDANDSHIELD_START );
		this->SetSprite( CHARIMAGE_PRIMARY_ATTACK_SWORDANDSHIELD_1			, FILEPATH_CHARIMAGE_PRIMARY_ATTACK_SWORDANDSHIELD_1 );
		this->SetSprite( CHARIMAGE_PRIMARY_ATTACK_SWORDANDSHIELD_END		, FILEPATH_CHARIMAGE_PRIMARY_ATTACK_SWORDANDSHIELD_END );
		//
		this->SetSprite( CHARIMAGE_SECONDARY_ATTACK_SWORDANDSHIELD_START	, FILEPATH_CHARIMAGE_SECONDARY_ATTACK_SWORDANDSHIELD_START );
		this->SetSprite( CHARIMAGE_SECONDARY_ATTACK_SWORDANDSHIELD_1		, FILEPATH_CHARIMAGE_SECONDARY_ATTACK_SWORDANDSHIELD_1	);
		this->SetSprite( CHARIMAGE_SECONDARY_ATTACK_SWORDANDSHIELD_2		, FILEPATH_CHARIMAGE_SECONDARY_ATTACK_SWORDANDSHIELD_2	);
		this->SetSprite( CHARIMAGE_SECONDARY_ATTACK_SWORDANDSHIELD_3		, FILEPATH_CHARIMAGE_SECONDARY_ATTACK_SWORDANDSHIELD_3	);
		this->SetSprite( CHARIMAGE_SECONDARY_ATTACK_SWORDANDSHIELD_4		, FILEPATH_CHARIMAGE_SECONDARY_ATTACK_SWORDANDSHIELD_4	);
		this->SetSprite( CHARIMAGE_SECONDARY_ATTACK_SWORDANDSHIELD_END		, FILEPATH_CHARIMAGE_SECONDARY_ATTACK_SWORDANDSHIELD_END );

		// All weapons locked
		this->weapon_level		= new int	[ CWeapon::TOTAL ];
		this->weapon_unlocked	= new bool	[ CWeapon::TOTAL ];

		for ( int i=0; i < CWeapon::TOTAL; i ++ )
		{
			// Lock all weapons
			this->Weapon_Unlock( static_cast<CWeapon::WEAPON>( i ), false );
			
			// All weapons level 1
			this->weapon_level[i] = 1;
		}

		// Initialised weapon unlocked
		this->Weapon_Unlock( weapon_choice );

		// Initialise character once
		this->Init( Vector3D(), 0, 0 );
	}

	// Select weapon
	if ( !Weapon_Select( weapon_choice ) ) return false;

	// Reset Character
	this->ResetCharacter( false, lives, move_speed );

	// Initialise Character	
	this->letOffset			= true;
	this->char_status_invul	= false;

	// Set Position
	this->Set_Character_Position( character_position );
	this->Set_Character_Position_HUD( hud_position );

	// Set Size
	this->SetSize( size.x, size.y );

	// Initialise Timer
	timer_weapon_timeallowed.StopTimer();
	timer_weapon_chargetime	.StopTimer();

	return true;
}

// Function that resets the character class
bool Character::ResetCharacter(const bool dead, const float lives, const float move_speed, const bool invertimage)
{
	this->char_hit				= false;
	this->char_dead				= dead;
	this->char_moving			= false;
	this->char_denymove			= false;
	this->char_attacking_pri	= false;
	this->char_attacking_sec	= false;
	this->char_attack_allow		= false;
	this->char_status_invul		= false;
	this->char_jumptracker		= 0.0f;

	this->invertImage			= invertimage;

	this->SetSpeed( move_speed );

	// Get level of weapon
	this->weapon_level[ weapon_weapon->GetWeaponTypeID() ] = weapon_weapon->GetLevel();

	// Dead
	if ( char_dead )
	{
		// No Lives Left
		this->SetLife( 0.0f );

		// Set death animation
		this->SetSpriteImageNumber( sprite_death_strt );
		this->sprite_anim_start		= sprite_death_strt;
		this->sprite_anim_end		= sprite_death_end;

		return false;
	}
	// Not Dead
	else
	{
		// Reset Lives
		this->SetLife( lives );

		// Set idle sprite
		this->SetSpriteImageNumber( sprite_idle_strt );
		this->sprite_anim_start		= sprite_idle_strt;
		this->sprite_anim_end		= sprite_idle_end;

		return true;
	}
}

// Update Character
bool Character::UpdateObject(float elapsed)
{
	// If character is not dead yet
	if ( !char_dead )
	{
		// If character is not hit
		if ( !char_hit )
		{
			// Jump
			if ( char_jumptracker > 0.0f )
			{
				// Calculate jump
				float temp = ( CHAR_SPEED_JUMP + GRAVITY ) * elapsed;

				// Jump up
				this->char_jumptracker	-= temp;
				this->hOff.y			= hOff.y - temp;
				
				// End jump
				if ( char_jumptracker < 0.0f )
				{
					this->hOff.y			-= char_jumptracker;
					this->char_jumptracker	= 0.0f;
				}
			}

			// If not attacking
			if ( !char_attacking_pri && !char_attacking_sec )
			{	
				// If on ground and not moving
				if ( this->GetOnGround() && !char_moving )
				{
					// Set idle sprite
					this->SetSpriteImageNumber( sprite_idle_strt );
					this->sprite_anim_start		= sprite_idle_strt;
					this->sprite_anim_end		= sprite_idle_end;

					this->timer_sprite_char	= TIMER_SPRITE_CHAR_IDLE;
				}
				// If not on ground
				else if ( !this->GetOnGround() )
				{
					// Set in air sprite
					this->SetSpriteImageNumber( sprite_inair_strt );
					this->sprite_anim_start = sprite_inair_strt;
					this->sprite_anim_end	= sprite_inair_end;

					this->timer_sprite_char	= TIMER_SPRITE_CHAR_INAIR;
				}
			}
		}

		// If character is not moving, reset direction to 0
		if ( !char_moving ) this->SetDirection( Vector3D( 0.0f, 0.0f, 0.0f ) );

		// Update Weapon Secondary Attack
		if		( weapon_weapon->GetWeaponTypeID() == CWeapon::DUALSWORD )		this->Weapon_Sec_Atk_Dualsword		( elapsed );
		else if	( weapon_weapon->GetWeaponTypeID() == CWeapon::SWORDANDSHIELD )	this->Weapon_Sec_Atk_SwordAndShield	( elapsed );
	}

	// If end of death animation
	if ( char_dead && animationFinished && GetSpriteImageNumber() == sprite_death_strt )
	{
		return this->ResetCharacter( true );
	}
	// If end of hurt animation
	else if ( animationFinished && GetSpriteImageNumber() == sprite_hurt_strt )
	{
		// If not dead yet
		if ( !char_dead )
		{
			this->char_status_invul = false;
			this->char_hit			= false;

			timer_char_status_invul_after_hit.StartTimer( 0, 0, 0, TIMER_CHAR_STATUS_INVUL_AFTER_HIT );
		}
		// If Dead, set to death sprite
		else if ( this->GetSpriteImageNumber() < sprite_death_strt || this->GetSpriteImageNumber() > sprite_death_end )
		{
			this->SetSpriteImageNumber( sprite_death_strt );
			this->sprite_anim_start = sprite_death_strt;
			this->sprite_anim_end	= sprite_death_end;

			this->timer_sprite_char	= TIMER_SPRITE_CHAR_DEATH;
		}
	}
	// If not dead yet
	else if ( !char_dead )
	{
		// If start of weapon animation
		if ( char_attack_allow && ( GetSpriteImageNumber() == sprite_pri_atk_do_atk || GetSpriteImageNumber() == sprite_sec_atk_do_atk ) )
		{
			// If start of primary attack animation
			if ( char_attacking_pri )
			{
				// Do primary attack
				this->weapon_weapon->AttackPrimaryAttack();

				// Do not apply weapon position offset
				this->weapon_offset_apply = false;
			}

			// If start of secondary attack animation
			if ( char_attacking_sec )
			{
				// Do secondary attack
				this->weapon_weapon->AttackSecondaryAttack();

				// Invulnerable during secondary attack
				this->char_status_invul = true;

				// Apply weapon position offset
				this->weapon_offset_apply = true;
			}

			// Only attack once
			this->char_attack_allow = false;
		}
		// If end of attack animation
		else if ( animationFinished && !char_attack_allow && ( GetSpriteImageNumber() == sprite_pri_atk_track_strt || GetSpriteImageNumber() == sprite_sec_atk_track_strt ) )
		{
			// Attack end
			this->weapon_weapon->AttackEnd();

			// Only end once
			this->char_attack_allow	= true;

			// If end of primary attack animation
			if ( char_attacking_pri ) this->char_attacking_pri = false;

			// If end of secondary attack animation
			if ( char_attacking_sec )
			{
				// Attack end
				this->char_attacking_sec = false;

				// No attack interval between secondary
				if ( weapon_weapon->GetWeaponTypeID() != CWeapon::DUALSWORD )
					this->weapon_weapon->AttackEndInterval();

				// Disable invulnerable status if existing
				if ( !weapon_sec_atk_key_hold && char_status_invul )
					this->char_status_invul = false;
			}
		}
		// If not attacking
		else if ( animationFinished && char_attack_allow && GetSpriteImageNumber() < sprite_pri_atk_track_strt && GetSpriteImageNumber() > sprite_pri_atk_track_end && GetSpriteImageNumber() < sprite_sec_atk_track_strt && GetSpriteImageNumber() > sprite_sec_atk_track_end )
		{
			// Can attack again
			this->char_attack_allow = false;
		}
	}

	// Play sprite animation
	this->PlaySpriteAnimation( sprite_anim_start, sprite_anim_end, timer_sprite_char );

	// Update character
	this->Object::UpdateObject( Vector3D( this->GetPosition() ), elapsed );

	// Update weapon position
	if ( invertImage )
	{
		// Weapon On The Left, And Face Left
		this->weapon_weapon->SetDirection( Vector3D( -1.0f, 0.0f, 0.0f ) );
		this->weapon_weapon->invertImage = true;

		// Apply offset if available
		if ( !weapon_offset_apply )	this->weapon_weapon->SetPosition( Vector3D( GetPosition().x - CHAR_SIZE_X, GetPosition().y, 0.0f ) );
		else						this->weapon_weapon->SetPosition( Vector3D( GetPosition().x - CHAR_SIZE_X - weapon_offset_sec.x, GetPosition().y + weapon_offset_sec.y, 0.0f ) );
	}
	else
	{
		// Weapon On The Right, And Face Right
		this->weapon_weapon->SetDirection( Vector3D( 1.0f, 0.0f, 0.0f ) );
		this->weapon_weapon->invertImage = false;

		if ( !weapon_offset_apply )	this->weapon_weapon->SetPosition( Vector3D( GetPosition().x + CHAR_SIZE_X, GetPosition().y, 0.0f ) );
		else						this->weapon_weapon->SetPosition( Vector3D( GetPosition().x + CHAR_SIZE_X + weapon_offset_sec.x, GetPosition().y + weapon_offset_sec.y, 0.0f ) );
	}

	// Update weapon
	this->weapon_weapon->UpdateObject( elapsed );

	// Update timers
	timer_char_status_invul_after_hit	.UpdateTimer();
	timer_weapon_timeallowed			.UpdateTimer();
	timer_weapon_chargetime				.UpdateTimer();

	return true;
}

// Draw Character
void Character::RenderObject(void)
{
	// Render character
	Object::RenderObject();

	// Render weapon
	this->weapon_weapon->RenderObject();
}

// Function for character to move left and/or right
bool Character::Move_Character_Horizontal(const bool direction_left, const float elapsed)
{
	// Only run if not dead
	if ( char_dead ) return false;

	// Can't move if secondary attack and not sword and shield
	if ( weapon_sec_atk_key_hold && weapon_weapon->GetWeaponTypeID() != CWeapon::SWORDANDSHIELD ) return false;

	// Move only if not hit and not attacking, or not on ground and primary attacking, or secondary attacking while not using longsword
	if ( !char_hit && !weapon_dualsword_tracker_move && ( ( !char_attacking_pri && !char_attacking_sec ) || ( char_attacking_pri && !GetOnGround() ) || ( char_attacking_sec && GetOnGround() && weapon_weapon->GetWeaponTypeID() == CWeapon::SWORDANDSHIELD ) ) )
	{
		// Moving
		this->char_moving = true;

		// Walk left
		if( direction_left )
		{
			// Direction left
			this->SetDirection( Vector3D( -1.0f, 0.0f, 0.0f ) );

			// Move left
			Object::MoveMeLeftRight( true, elapsed );
		}
		// Walk right
		else
		{
			// Direction right
			this->SetDirection( Vector3D( 1.0f, 0.0f, 0.0f ) );

			// Move right
			Object::MoveMeLeftRight( false, elapsed );
		}

		// Only on the ground
		if ( GetOnGround() && !char_attacking_sec )
		{
			// Set to moving sprite
			if ( this->GetSpriteImageNumber() < sprite_move_strt || this->GetSpriteImageNumber() > sprite_move_end )
			{
				this->SetSpriteImageNumber( sprite_move_strt );
				this->sprite_anim_start = sprite_move_strt;
				this->sprite_anim_end	= sprite_move_end;
				
				this->timer_sprite_char	= TIMER_SPRITE_CHAR_MOVE;
			}

			return true;
		}
	}

	return false;
}

// Function for character to jump
bool Character::Move_Character_Jump(void)
{
	// Only run if not dead
	if ( char_dead ) return false;

	if ( char_jumptracker == 0.0f && !char_hit && !weapon_dualsword_tracker_move && this->GetOnGround() && !char_attacking_pri && !char_attacking_sec )
	{
		this->char_jumptracker = CHAR_LIMIT_JUMP;
		return true;
	}

	return false;
}
// Function for character to do attack ( primary == true / secondary == false )
bool Character::Move_Character_Attack(const bool primary)
{
	// Only run if not dead
	if ( char_dead ) return false;

	if ( !char_attacking_sec  )
 
	if ( !char_hit && !weapon_dualsword_tracker_move && !char_attacking_pri && !char_attacking_sec )
	{
		// Do primary attack
		if ( primary && weapon_weapon->CheckAttackDelayEnd() )
		{
			// Attacking
			this->char_attacking_pri	= true;
			this->char_attack_allow		= true;

			// Set to primary attack sprite
			if ( this->GetSpriteImageNumber() < sprite_pri_atk_track_strt  || this->GetSpriteImageNumber() > sprite_pri_atk_track_end )
			{
				this->SetSpriteImageNumber( sprite_pri_atk_track_strt );
				this->sprite_anim_start = sprite_pri_atk_track_strt;
				this->sprite_anim_end	= sprite_pri_atk_track_end;

				this->timer_sprite_char	= TIMER_SPRITE_CHAR_PRIMARY;
			}
			return true;
		}
		// Do secondary attack
		else if ( !primary && GetOnGround() && char_jumptracker == 0.0f )
		{
			// Check if sword and shield
			if ( weapon_weapon->GetWeaponTypeID() == CWeapon::SWORDANDSHIELD )
			{
				// Can't use secondary attack if not available
				if ( timer_weapon_timeallowed.CheckIfTimerEnd() )
				{
					// Disable invulnerable status if existing
					if ( char_status_invul ) this->char_status_invul = false;

					return false;
				}

				// Start using again
				timer_weapon_timeallowed.PauseTimer( false );
			}
			// Check if dualsword
			else if ( weapon_weapon->GetWeaponTypeID() == CWeapon::DUALSWORD && timer_weapon_chargetime.CheckIfTimerRunning() ) return false;
			
			// Attacking
			this->char_attacking_sec		= true;
			this->char_attack_allow			= true;

			// Key is held down
			this->weapon_sec_atk_key_hold	= true;

			// Set to secondary attack sprite
			if ( this->GetSpriteImageNumber() < sprite_sec_atk_track_strt  || this->GetSpriteImageNumber() > sprite_sec_atk_track_end )
			{
				this->SetSpriteImageNumber( sprite_sec_atk_track_strt );
				this->sprite_anim_start = sprite_sec_atk_track_strt;
				this->sprite_anim_end	= sprite_sec_atk_track_end;

				this->timer_sprite_char	= TIMER_SPRITE_CHAR_SECONDARY;
			}
			return true;
		}
	}

	return false;
}

// Function that does the necessary for when the character has been hit by something
void Character::ReduceLife(float life_reduce_by)
{
	// Only run if not dead, invulnerable, or hit
	if ( char_dead || char_status_invul || char_hit || !timer_char_status_invul_after_hit.CheckIfTimerEnd() ) return;

	// Set movement
	this->char_hit				= true;
	this->char_moving			= false;
	this->char_attacking_pri	= false;
	this->char_attacking_sec	= false;
	this->char_jumptracker		= 0.0f;

	// Invulnerable when hit
	this->char_status_invul		= true;

	// Reduce life
	Object::ReduceLife( life_reduce_by );

	// Check if dead
	if ( Check_Lives_Dead() ) this->char_dead = true;

	// If not dead, set to hurt sprite
	if ( this->GetSpriteImageNumber() < sprite_hurt_strt || this->GetSpriteImageNumber() > sprite_hurt_end )
	{
		this->SetSpriteImageNumber( sprite_hurt_strt );
		this->sprite_anim_start = sprite_hurt_strt;
		this->sprite_anim_end	= sprite_hurt_end;

		this->timer_sprite_char	= TIMER_SPRITE_CHAR_HURT;
	}
}

// Dualsword Secondary Attack Movement
void Character::Weapon_Sec_Atk_Dualsword(const float elapsed)
{
	// Only run if not dead
	if ( char_dead ) return;

	// Dualsword movement tracker
	static float weapon_dualsword_tracker_x = 0.0f;

	// If animation started
	if ( char_attacking_sec && !weapon_dualsword_tracker_move && timer_weapon_chargetime.CheckIfTimerEnd() )
	{
		weapon_dualsword_tracker_x			= 0.0f;

		this->weapon_dualsword_tracker_move	= true;
		this->char_moving					= false;

		this->timer_weapon_chargetime.StartTimer( 0, 0, 0, WEAPON_DUELSWORD_CHARGE_TIME );
	}
	// Move back
	else if ( weapon_dualsword_tracker_move && weapon_dualsword_tracker_x < WEAPON_DUELSWORD_MOVEBACK_X_LIMIT )
	{
		// Calculate movement
		float temp = WEAPON_DUELSWORD_MOVEBACK_X_SPEED * elapsed;

		// Update tracker
		weapon_dualsword_tracker_x += temp;

		// If able to move
		if ( !char_denymove )
		{
			// Move right
			if ( invertImage )	this->SetDirection( Vector3D( 1.0f, 0.0f, 0.0f ) );
			// Move left
			else				this->SetDirection( Vector3D( -1.0f, 0.0f, 0.0f ) );
		}
		// Not able to move
		else this->SetDirection( Vector3D() );

		// Move
		this->hOff.x = hOff.x + this->GetDirection().x * temp;

		// Check if finished moving
		if ( weapon_dualsword_tracker_x >= WEAPON_DUELSWORD_MOVEBACK_X_LIMIT ) 
		{
			// Check right
			if ( invertImage )	this->hOff.x = hOff.x - ( weapon_dualsword_tracker_x - WEAPON_DUELSWORD_MOVEBACK_X_LIMIT );
			// Check left
			else				this->hOff.x = hOff.x + ( weapon_dualsword_tracker_x - WEAPON_DUELSWORD_MOVEBACK_X_LIMIT );

			// End animation
			this->weapon_dualsword_tracker_move = false;
		}
	}
}

// SwordAndShield Secondary Attack Movement
void Character::Weapon_Sec_Atk_SwordAndShield(const float elapsed)
{	
	// Only run if not dead
	if ( char_dead ) return;

	// If using
	if ( timer_weapon_timeallowed.CheckIfTimerRunning() )
	{
		// Do not charge
		timer_weapon_chargetime.StartTimer( 0, 0, 0, WEAPON_SWORDANDSHIELD_CHARGE_TIME );
	}

	// If charged finish
	if ( timer_weapon_chargetime.CheckIfTimerEnd() && !timer_weapon_timeallowed.CheckIfTimerRunning() && timer_weapon_timeallowed.GetTimeLeft() < WEAPON_SWORDANDSHIELD_TIME_ALLOWED )
	{
		// Allocate fresh time allowed
		timer_weapon_timeallowed.StartTimer( 0, 0, 0, WEAPON_SWORDANDSHIELD_TIME_ALLOWED );

		// Pause timer
		timer_weapon_timeallowed.PauseTimer( true );
	}
}

// Release of secondary attack key
void Character::Weapon_Sec_Atk_Stop_Hold(void)
{
	// Only run if not dead
	if ( char_dead ) return;

	// Sword and Shield
	if ( weapon_weapon->GetWeaponTypeID() == CWeapon::SWORDANDSHIELD )
	{
		// Stop using
		if ( !timer_weapon_timeallowed.CheckIfTimerEnd() )
		{
			// Stop using timer
			timer_weapon_timeallowed.PauseTimer( true );
		}
		else
		{
			// End timer
			timer_weapon_timeallowed.StopTimer();
		}

		// Charge upon release
		if ( !timer_weapon_timeallowed.CheckIfTimerRunning() && !timer_weapon_chargetime.CheckIfTimerRunning() && !( timer_weapon_timeallowed.GetTimeLeft() < WEAPON_SWORDANDSHIELD_TIME_ALLOWED ) )
			timer_weapon_chargetime.StartTimer( 0, 0, 0, WEAPON_SWORDANDSHIELD_CHARGE_TIME );
	}
	
	// Key is released
	this->weapon_sec_atk_key_hold = false;
}

// Function to level weapon
bool Character::Weapon_Level(const CWeapon::WEAPON weapon, const int amount)
{
	// Only if weapon exists
	if ( weapon < 0 || weapon >= CWeapon::TOTAL ) return false;

	// Level up weapon
	this->weapon_level[ weapon ] += amount;

	// Weapon leveled
	return true;
}

// Function to lock/unlock weapon
bool Character::Weapon_Unlock(const CWeapon::WEAPON weapon, const bool unlock)
{
	// Only if weapon exists
	if ( weapon < 0 || weapon >= CWeapon::TOTAL ) return false; 

	// Unlock/unlock weapon
	this->weapon_unlocked[ weapon ] = unlock;

	// Weapon unlocked/locked
	return true;
}

// Function to select weapon character uses
bool Character::Weapon_Select(const CWeapon::WEAPON weapon)
{
	// Only if weapon exists
	if ( weapon < 0 || weapon >= CWeapon::TOTAL ) return false;

	// Only if weapon is unlocked
	if ( !weapon_unlocked[ weapon ] ) return false;

	// Only can select if initialised
	if ( weapon_unlocked != NULL && weapon_unlocked[ weapon ] != NULL )
	{
		// Initialise textures
		this->sprite_idle_strt	= CHARIMAGE_IDLE_START;
		this->sprite_idle_end	= CHARIMAGE_IDLE_END;

		this->sprite_inair_strt	= CHARIMAGE_INAIR_START;
		this->sprite_inair_end	= CHARIMAGE_INAIR_END;

		this->sprite_hurt_strt	= CHARIMAGE_HURT_START;
		this->sprite_hurt_end	= CHARIMAGE_HURT_END;

		this->sprite_death_strt	= CHARIMAGE_DEATH_START;
		this->sprite_death_end	= CHARIMAGE_DEATH_END;

		this->sprite_move_strt	= CHARIMAGE_MOVE_START;
		this->sprite_move_end	= CHARIMAGE_MOVE_END;

		// Safeguard
		if ( weapon_weapon != NULL )
		{
			delete weapon_weapon;
			weapon_weapon = NULL;
		}

		// Weapon
		switch( weapon )
		{
			// Dualsword
		case CWeapon::DUALSWORD:
			{
				this->sprite_pri_atk_track_strt = CHARIMAGE_PRIMARY_ATTACK_DUALSWORD_START;
				this->sprite_pri_atk_track_end	= CHARIMAGE_PRIMARY_ATTACK_DUALSWORD_END;
				this->sprite_pri_atk_do_atk		= CHARIMAGE_PRIMARY_ATTACK_DUALSWORD_1;

				this->sprite_sec_atk_track_strt = CHARIMAGE_SECONDARY_ATTACK_DUALSWORD_START;
				this->sprite_sec_atk_track_end	= CHARIMAGE_SECONDARY_ATTACK_DUALSWORD_END;
				this->sprite_sec_atk_do_atk		= CHARIMAGE_SECONDARY_ATTACK_DUALSWORD_START;

				this->weapon_offset_sec			= Vector3D( -CHAR_SIZE_X, -CHAR_SIZE_Y / 3 * 2.5, 0.0f );

				if ( weapon_weapon == NULL )
				{
					this->weapon_weapon = new CDualSword();

					CDualSword* temp = dynamic_cast<CDualSword*>( weapon_weapon );
					temp->Initialise( CHAR_SIZE_X, CHAR_SIZE_Y, weapon_level[ CWeapon::DUALSWORD ] );
				}
			}
			break;

			// Longsword
		case CWeapon::LONGSWORD:
			{
				this->sprite_pri_atk_track_strt = CHARIMAGE_PRIMARY_ATTACK_LONGSWORD_START;
				this->sprite_pri_atk_track_end	= CHARIMAGE_PRIMARY_ATTACK_LONGSWORD_END;
				this->sprite_pri_atk_do_atk		= CHARIMAGE_PRIMARY_ATTACK_LONGSWORD_1;

				this->sprite_sec_atk_track_strt = CHARIMAGE_SECONDARY_ATTACK_LONGSWORD_START;
				this->sprite_sec_atk_track_end	= CHARIMAGE_SECONDARY_ATTACK_LONGSWORD_END;
				this->sprite_sec_atk_do_atk		= CHARIMAGE_SECONDARY_ATTACK_LONGSWORD_START;

				this->weapon_offset_sec			= Vector3D( -CHAR_SIZE_X, -CHAR_SIZE_Y / 3 * 2.5, 0.0f );

				if ( weapon_weapon == NULL )
				{
					this->weapon_weapon = new CLongsword();

					CLongsword* temp = dynamic_cast<CLongsword*>( weapon_weapon );
					temp->Initialise( CHAR_SIZE_X, CHAR_SIZE_Y, weapon_level[ CWeapon::LONGSWORD ] );
				}
			}
			break;

			// Sword And Shield
		default:
			{
				this->sprite_pri_atk_track_strt = CHARIMAGE_PRIMARY_ATTACK_SWORDANDSHIELD_START;
				this->sprite_pri_atk_track_end	= CHARIMAGE_PRIMARY_ATTACK_SWORDANDSHIELD_END;
				this->sprite_pri_atk_do_atk		= CHARIMAGE_PRIMARY_ATTACK_SWORDANDSHIELD_1;

				this->sprite_sec_atk_track_strt = CHARIMAGE_SECONDARY_ATTACK_SWORDANDSHIELD_START;
				this->sprite_sec_atk_track_end	= CHARIMAGE_SECONDARY_ATTACK_SWORDANDSHIELD_END;
				this->sprite_sec_atk_do_atk		= CHARIMAGE_SECONDARY_ATTACK_SWORDANDSHIELD_START;

				this->weapon_offset_sec			= Vector3D( -CHAR_SIZE_X, -CHAR_SIZE_Y / 3 * 2.5, 0.0f );

				if ( weapon_weapon == NULL )
				{
					this->weapon_weapon = new CSwordAndShield();

					CSwordAndShield* temp = dynamic_cast<CSwordAndShield*>( weapon_weapon );
					temp->Initialise( CHAR_SIZE_X, CHAR_SIZE_Y, weapon_level[ CWeapon::SWORDANDSHIELD ] );
				};
			}
		}

		// Weapon selected
		return true;
	}

	// Unable to select a weapon
	return false;
}

// Save function
bool Character::Save(const char* filename)
{
	// Creating File
	ofstream file;
	file.open( filename, ios::trunc );

	// If Does Not Exist Or Cannot Open
	if ( file == NULL || !file.is_open() ) return false;

	// Save character data
	if ( weapon_weapon != NULL )
	{
		file << "char,using," << weapon_weapon->GetWeaponTypeID() << "\n";
	}
	else
	{
		file << "char,using," << WEAPONDEFAULT << "\n";
	}

	// Save weapon data
	if ( weapon_unlocked != NULL && weapon_level != NULL )
	{
		for ( int i=0; i < CWeapon::TOTAL; i ++ )
			file << "wep," << i << "," << weapon_unlocked[i] << "," << weapon_level[i] << "\n";
	}
	else
	{
		file << "wep,0,1,1\n";

		for ( int i=1; i < CWeapon::TOTAL; i ++ )
			file << "wep," << i << ",0,1\n";
	}

	// Save inventory data
	if ( theInventory != NULL )
	{
		for ( int i=0; i < theInventory->ReturnRow(); i ++ )
			for ( int j=0; j < theInventory->ReturnColumn(); j ++ )
				if ( theInventory->ReturnInventory( i, j ) != Item::NOTHING )
					file << "inv," << theInventory->ReturnInventory( i, j ) << "\n";
	}

	// Save notify
	if ( PRINTSAVE ) printf( "File '%s' has been created and saved.\n", filename );

	// Close File
	file.close();
	return true;
}

// Load function
bool Character::Load(const char* filename)
{
	// Open File
	ifstream file;
	file.open( filename );

	// If Does Not Exist
	if ( file == NULL )
	{
		// Create File
		if ( !Save( filename ) ) return false;

		// Reopen File
		file.close();
		file.open( filename );
	}

	// Initialise File
	file.clear();
	file.seekg( 0, file.beg );

	// To Read Data In The File
	string	data_read = "",
			data_token = "";

	// File Is Healthy
	while ( file.good() )
	{
		// Read Data
		data_read	= "";
		data_token	= "";
		getline( file, data_read );
		stringstream iss( data_read );

		// Load Character
		if ( data_read.find( "char,using," ) == NULL )
		{
			// Go Through And Read Data
			for ( int i=-1; i < 2; i ++ )
				getline( iss, data_token, ',' );

			// Make Sure Targeted Weapon Exists
			if ( atoi( data_token.c_str() ) < 0 || atoi( data_token.c_str() ) >= CWeapon::TOTAL ) return false;

			// Put In Data
			if ( !Initialise( static_cast< CWeapon::WEAPON >( atoi( data_token.c_str() ) ) ) ) return false;

			// Announce Loaded
			if ( PRINTLOAD ) printf( "LOADED->CHARACTER[ %d ]\n", atoi( data_token.c_str() ) );
		}

		// Load Weapons
		else if ( data_read.find( "wep," ) == NULL )
		{
			// Check For Errors
			if ( weapon_unlocked == NULL || weapon_level == NULL )
			{
				if (	!Initialise		( CWeapon::DUALSWORD )			||
						!Weapon_Unlock	( CWeapon::DUALSWORD, false )	)
					return false;
			}

			// Weapons Load Tracker
			int temp_wep = -1;

			// Read Data
			for ( int i=-1; getline( iss, data_token, ',' ); i ++ )
			{
				// Put In Data
				if ( i == 0 )
				{
					// Point To Targeted Weapon
					temp_wep = atoi( data_token.c_str() );

					// Make Sure Targeted Weapon Exists
					if ( temp_wep < 0 || temp_wep >= CWeapon::TOTAL ) return false;
				}
				else if	( i == 1 )
				{
					// Unlocked
					this->weapon_unlocked	[ temp_wep ]	= static_cast<bool>( atoi( data_token.c_str() ) );
				}
				else if	( i == 2 )
				{
					// Level
					this->weapon_level		[ temp_wep ]	= atoi( data_token.c_str() );
				}
			}

			// Announce Loaded
			if ( PRINTLOAD ) printf( "LOADED->WEAPON[ %d ][ %d ][ %d ]\n", temp_wep, static_cast<int>( weapon_unlocked[ temp_wep ] ), weapon_level[ temp_wep ] );
		}

		// Load Inventory
		else if ( data_read.find( "inv," ) == NULL )
		{
			// Go Through And Read Data
			for ( int i=-1; i < 2; i ++ )
				getline( iss, data_token, ',' );

			// Add Data
			theInventory->AddItem( Item( static_cast< Item::no >( atoi( data_token.c_str() ) )) );

			// Announce Loaded
			if ( PRINTLOAD ) printf( "LOADED->ITEM[ %d ]\n", atoi( data_token.c_str() ) );

		}
	}

	// Close File
	file.close();
	return true;
}